xenpaging: add watch thread to catch guest shutdown
authorOlaf Hering <olaf@aepfle.de>
Fri, 10 Jun 2011 08:47:27 +0000 (10:47 +0200)
committerOlaf Hering <olaf@aepfle.de>
Fri, 10 Jun 2011 08:47:27 +0000 (10:47 +0200)
If xenpaging is started manually then no event is sent to xenpaging when
the guest is shutdown or rebooted.  Add a watch on the @releaseDomain
node to leave the loop and gracefully shutdown the pager.

Signed-off-by: Olaf Hering <olaf@aepfle.de>
Committed-by: Ian Jackson <ian.jackson.citrix.com>
tools/xenpaging/xenpaging.c

index 72daaad164d0fbe42a0988e664e1c6d14d49df2d..55e00e60e3111290809411bf5f1507b13bc7ecb4 100644 (file)
@@ -39,6 +39,7 @@
 #include "policy.h"
 #include "xenpaging.h"
 
+static char watch_token[16];
 static char filename[80];
 static int interrupted;
 
@@ -75,13 +76,19 @@ static int xenpaging_wait_for_event_or_timeout(xenpaging_t *paging)
 {
     xc_interface *xch = paging->xc_handle;
     xc_evtchn *xce = paging->mem_event.xce_handle;
-    struct pollfd fd[1];
+    char **vec;
+    unsigned int num;
+    struct pollfd fd[2];
     int port;
     int rc;
 
+    /* Wait for event channel and xenstore */
     fd[0].fd = xc_evtchn_fd(xce);
     fd[0].events = POLLIN | POLLERR;
-    rc = poll(fd, 1, 100);
+    fd[1].fd = xs_fileno(paging->xs_handle);
+    fd[1].events = POLLIN | POLLERR;
+
+    rc = poll(fd, 2, 100);
     if ( rc < 0 )
     {
         if (errno == EINTR)
@@ -91,6 +98,27 @@ static int xenpaging_wait_for_event_or_timeout(xenpaging_t *paging)
         return -errno;
     }
 
+    /* First check for guest shutdown */
+    if ( rc && fd[1].revents & POLLIN )
+    {
+        DPRINTF("Got event from xenstore\n");
+        vec = xs_read_watch(paging->xs_handle, &num);
+        if ( vec )
+        {
+            if ( strcmp(vec[XS_WATCH_TOKEN], watch_token) == 0 )
+            {
+                /* If our guest disappeared, set interrupt flag and fall through */
+                if ( xs_is_domain_introduced(paging->xs_handle, paging->mem_event.domain_id) == false )
+                {
+                    xs_unwatch(paging->xs_handle, "@releaseDomain", watch_token);
+                    interrupted = SIGQUIT;
+                    rc = 0;
+                }
+            }
+            free(vec);
+        }
+    }
+
     if ( rc && fd[0].revents & POLLIN )
     {
         DPRINTF("Got event from evtchn\n");
@@ -165,6 +193,14 @@ static xenpaging_t *xenpaging_init(domid_t domain_id, int num_pages)
         goto err;
     }
 
+    /* write domain ID to watch so we can ignore other domain shutdowns */
+    snprintf(watch_token, sizeof(watch_token), "%u", domain_id);
+    if ( xs_watch(paging->xs_handle, "@releaseDomain", watch_token) == false )
+    {
+        ERROR("Could not bind to shutdown watch\n");
+        goto err;
+    }
+
     p = getenv("XENPAGING_POLICY_MRU_SIZE");
     if ( p && *p )
     {